import { Injectable, Logger } from "@nestjs/common";
import { RedisService } from "./redis.service";
import { UserEntity } from "../entities/user.entity";
import { randomBytes, createHash } from "crypto";

export interface UserTokenData {
  userId: number;
  mobile: string;
  token: string;
  selectedCharacterId?: number;
  characterName?: string;
  loginTime: number;
  lastActiveTime: number;
}

export interface ActiveSessionData {
  sessionId: string;
  token: string;
  wsClientId?: string;
  device?: string;
  issuedAt: number;
}

@Injectable()
export class UserAuthService {
  private readonly logger = new Logger(UserAuthService.name);
  private readonly TOKEN_TTL = 86400; // 24小时过期
  private readonly USER_DATA_TTL = 86400; // 24小时过期

  constructor(private readonly redisService: RedisService) {}

  /**
   * 用户登录成功后，将token信息存储在Redis缓存中
   */
  async storeUserToken(user: UserEntity, token: string): Promise<void> {
    try {
      // 检查用户是否已经登录过，如果登录过需要删除之前的token缓存
      const existingUserData = await this.redisService.get(`user:${user.id}`);
      if (existingUserData) {
        try {
          const existingTokenData: UserTokenData = JSON.parse(existingUserData);
          if (existingTokenData.token && existingTokenData.token !== token) {
            // 删除之前的token缓存
            await this.redisService.del(`token:${existingTokenData.token}`);
            this.logger.log(
              `删除用户之前的token缓存: userId=${
                user.id
              }, oldToken=${existingTokenData.token.substring(0, 8)}...`
            );
          }
        } catch (parseError) {
          this.logger.warn(
            `解析用户现有缓存数据失败: userId=${user.id}`,
            parseError
          );
        }
      }

      const tokenData: UserTokenData = {
        userId: user.id,
        mobile: user.mobile,
        token,
        loginTime: Date.now(),
        lastActiveTime: Date.now(),
      };

      // 存储token到用户ID的映射
      await this.redisService.set(
        `token:${token}`,
        JSON.stringify(tokenData),
        this.TOKEN_TTL
      );

      // 存储用户ID到用户数据的映射
      await this.redisService.set(
        `user:${user.id}`,
        JSON.stringify(tokenData),
        this.USER_DATA_TTL
      );

      this.logger.log(
        `用户登录成功，token已缓存: userId=${user.id}, mobile=${user.mobile}`
      );

      // 设置活跃会话（单点登录）：生成新会话并覆盖
      const newSession: ActiveSessionData = {
        sessionId: this.generateSessionId(),
        token,
        issuedAt: Date.now(),
      };
      const activeKey = `user:active_session:${user.id}`;
      const prevActiveRaw = await this.redisService.get(activeKey);
      await this.redisService.set(
        activeKey,
        JSON.stringify(newSession),
        this.USER_DATA_TTL
      );

      // 发布踢线事件（通知其他实例踢掉旧连接）
      try {
        await this.redisService.publish(
          "user:kick",
          JSON.stringify({ userId: user.id, reason: "new_login" })
        );
      } catch (pubErr) {
        this.logger.warn(`发布踢线事件失败: userId=${user.id}`, pubErr as any);
      }
    } catch (error) {
      this.logger.error(`存储用户token失败: userId=${user.id}`, error);
      throw error;
    }
  }

  /**
   * 从token获取用户信息
   */
  async getUserFromToken(token: string): Promise<UserTokenData | null> {
    try {
      const cachedData = await this.redisService.get(`token:${token}`);
      if (!cachedData) {
        return null;
      }

      const userData: UserTokenData = JSON.parse(cachedData);

      // 更新最后活跃时间
      userData.lastActiveTime = Date.now();
      await this.redisService.set(
        `token:${token}`,
        JSON.stringify(userData),
        this.TOKEN_TTL
      );

      return userData;
    } catch (error) {
      this.logger.error(
        `从token获取用户信息失败: ${token.substring(0, 8)}...`,
        error
      );
      return null;
    }
  }

  /**
   * 更新用户选择的角色信息
   */
  async updateUserCharacter(
    userId: number,
    characterId: number,
    characterName: string
  ): Promise<void> {
    try {
      // 更新token缓存中的角色信息
      const userData = await this.redisService.get(`user:${userId}`);
      if (userData) {
        const parsed: UserTokenData = JSON.parse(userData);
        parsed.selectedCharacterId = characterId;
        parsed.characterName = characterName;
        parsed.lastActiveTime = Date.now();

        await this.redisService.set(
          `user:${userId}`,
          JSON.stringify(parsed),
          this.USER_DATA_TTL
        );
      }

      // 更新角色选择状态缓存
      await this.redisService.set(
        `user:selected_character:${userId}`,
        JSON.stringify({
          characterId,
          characterName,
          updated_at: Date.now(),
        }),
        86400 // 24小时过期
      );

      this.logger.log(
        `用户角色选择已更新: userId=${userId}, characterId=${characterId}, name=${characterName}`
      );
    } catch (error) {
      this.logger.error(`更新用户角色选择失败: userId=${userId}`, error);
      throw error;
    }
  }

  /**
   * 验证token是否有效
   */
  async validateToken(token: string): Promise<boolean> {
    try {
      const userData = await this.getUserFromToken(token);
      return userData !== null;
    } catch (error) {
      return false;
    }
  }

  /**
   * 用户登出，清除token缓存
   */
  async logout(token: string): Promise<void> {
    try {
      const userData = await this.getUserFromToken(token);
      if (userData) {
        // 删除token缓存
        await this.redisService.del(`token:${token}`);
        // 删除用户数据缓存
        await this.redisService.del(`user:${userData.userId}`);
        // 删除角色选择缓存
        await this.redisService.del(
          `user:selected_character:${userData.userId}`
        );
        // 清理活跃会话（如果token匹配当前活跃token）
        const activeKey = `user:active_session:${userData.userId}`;
        try {
          const activeRaw = await this.redisService.get(activeKey);
          if (activeRaw) {
            const active: ActiveSessionData = JSON.parse(activeRaw);
            if (active.token === token) {
              await this.redisService.del(activeKey);
            }
          }
        } catch {}

        this.logger.log(`用户登出成功，缓存已清除: userId=${userData.userId}`);
      }
    } catch (error) {
      this.logger.error(`用户登出失败: ${token.substring(0, 8)}...`, error);
      throw error;
    }
  }

  /**
   * 获取用户当前选择的角色信息
   */
  async getUserSelectedCharacter(userId: number): Promise<{
    characterId?: number;
    characterName?: string;
  } | null> {
    try {
      const cached = await this.redisService.get(
        `user:selected_character:${userId}`
      );
      if (cached) {
        return JSON.parse(cached);
      }
      return null;
    } catch (error) {
      this.logger.error(`获取用户角色选择失败: userId=${userId}`, error);
      return null;
    }
  }

  /** 获取活跃会话 */
  async getActiveSession(userId: number): Promise<ActiveSessionData | null> {
    try {
      const raw = await this.redisService.get(`user:active_session:${userId}`);
      return raw ? (JSON.parse(raw) as ActiveSessionData) : null;
    } catch (e) {
      return null;
    }
  }

  /** 仅当 sessionId 匹配时，绑定 wsClientId（防止并发串写） */
  async bindWsClientId(
    userId: number,
    sessionId: string,
    wsClientId: string
  ): Promise<boolean> {
    const key = `user:active_session:${userId}`;
    const raw = await this.redisService.get(key);
    if (!raw) return false;
    try {
      const active = JSON.parse(raw) as ActiveSessionData;
      if (active.sessionId !== sessionId) return false;
      active.wsClientId = wsClientId;
      await this.redisService.set(
        key,
        JSON.stringify(active),
        this.USER_DATA_TTL
      );
      return true;
    } catch {
      return false;
    }
  }

  private generateSessionId(): string {
    return createHash("md5").update(randomBytes(32)).digest("hex");
  }
}
